导航菜单
首页 >  编写 Restful 风格的 API 接口正确姿势  > 编写 Restful 风格的 API 接口正确姿势

编写 Restful 风格的 API 接口正确姿势

编写 Restful 风格的 API 接口正确姿势老牧童•2024-07-12 20:15•未分类•阅读 116

编写 Restful 风格的 API 接口正确姿势目前微服务架构盛行,在了解了很多的实际微服务项目中,发现很多同时在设计业务 API 接口时,写法五花八门,现总结下目前项目上设计业务 API 接

大家好,欢迎来到IT知识分享网。

背景

目前微服务架构盛行,在了解了很多的实际微服务项目中,发现很多同时在设计业务 API 接口时,写法五花八门,现总结下目前项目上设计业务 API 接口的一些比较经典误区写法。

Restful 架构风格下,API 接口设计经典误区写法1、查询某个对象接口:GET /app/getImportantApp@GetMapping(path = "/getImportantApp") public R getImportionApp(@RequestHeader("pid") String pid2、查询列表接口:GET /app/list@RequestMapping("/list") public R list(String deptId) 3、保存对象接口:POST /app/save@PostMapping("/save") public R add(CmsAppLicationEntity appLication, String deptId) 4、删除对象接口:POST /app/delete@DeleteMapping("/delete/{applicationId}") public R delete(@PathVariable("applicationId") long applicationId) 5、更新对象接口:POST /app/batchUpdate@PostMapping("/batchUpdate") public R batchUpdate(@RequestBody List list) 

是不是感觉很熟悉的代码,难道写的不对?看着挺直观易懂的。如果采用 Restful 架构风格,上面这五种写法当然不对,这是对 Restful 架构风格不了解所致。

微信搜公众号「猿芯」,后台私信回复 1024 免费领取 SpringCloud、SpringBoot,微信小程序、Java面试、数据结构、算法等全套视频资料。

Restful 架构风格定义

Restful 是一种软件架构风格、设计风格,而不是标准,只是提供了一组设计原则和约束条件。它主要用于客户端和服务器交互类的软件。基于这个风格设计的软件可以更简洁,更有层次,更易于实现缓存等机制。

由于对 Restful 架构风格理解的不够透彻,一般会产生三种争议的设计误区。

误区一 请求路径 URI 是动词,而不是名词问题误区二 URI中带版本号问题误区三 URI 中路径大小写问题误区一 请求路径 URI 是动词,而不是名词问题

按照对 Restful 架构风格理解,每个业务实体代表一种资源,代表一个名词。

比方说,设计产品列表接口时:

错误写法

/getProductList

请求路径 /getProductList 路径出现动词 get,这种写法是不对的。

推荐写法

/products

另外 URL 出现 /addProduct、/deleteProduct、/updateProduct 等写法也是不对的。

如果某些动作是 HTTP 动词表示不了的,你应该把该动作变成一种资源。

比方说,我们获取用户下的产品列表,错误接口设计是:

POST /users/1/getProducts

或者

POST /users/1/getProductList

正确的写法是把动词 getProducts 改成名词 products

POST /users/1/products误区二 URI 中带版本号问题

业界对 URI 中是否带版本号存在三种说法。

第一种说法是,在请求路径中加入版本号,比方说:

POST /products/v1 GET /users/v1 POST /orders/v1 POST /items/v1

这种说法认为,在 URI 中加入版本避免了向后兼容,另外通过过期提示,重定向,文档等手段也能降低用户迁移到新的接口上的成本。

当然有人赞成在请求路径中加入版本号,也有人反对这种加版本号的做法,他们认为:

加入版本号会让服务接口变得混乱,经常碰到的情况是,一些低版本的API接口调用一些高版本的API接口,导致数据解析错误,这无疑加大了用户迁移的成本。版本和资源的概念没有任何关系,因此在 URI 中加入版本会让用户混淆。

还有一种说法是,在路径中加版本号是错误的设计方式,在老外写的 Versioning REST Services 这篇文章指出,你应该在请求头的 Accept 指定你的版本号,而不是请求路径中。

例如:

For example, for versions 1.0, 1.1, and 2.0 of the foo data type as JSON set the Accept/Content-Type header as follows: 1.0: vnd.example-com.foo+json; version=1.0 1.1: vnd.example-com.foo+json; version=1.1 2.0: vnd.example-com.foo+json; version=2.0

前端 js 在请求头 Accept 指定 vnd.example-com.foo+json; version=1.1 的版本 version=1.1。

$.ajax({     beforeSend: function (req) {         req.setRequestHeader("Accept", "vnd.example-com.foo+json; version=1.1");          },     type: "GET",     url: "http://http://www.example.com/foo/12",     success: function (data) {         /* code elided */     },     dataType: "json" });

我个人是比较倾向请求路径中加版本号的,因为我认为加版本号是站在程序角度来考虑新老版本的接口移植问题,特别是现在流行微服务架构,业务粒度很细的情况下,接口的升级,原有版本是否保留呢?

微信搜公众号「猿芯」,后台私信回复 1024 免费领取 SpringCloud、SpringBoot,微信小程序、Java面试、数据结构、算法等全套视频资料。

那什么时候该加版本号呢?

如果你开发的 restful 接口是开放的,你也不知道都有谁调用过,那么这个时候版本号就是必须的了。以百度地图接口为例,百度发布了 restful 风格的地图接口在网上,全国甚至全世界各行各业都可以调用这些接口,百度要对接口进行升级,该怎么办?如果百度直接在原有的url上进行升级,会产生什么样的结果呢?不可预估。程序员:老板,咱们的产品崩溃了!老板:为啥?程序员:百度升级了接口!哪怕仅仅是多返回了一个字段,都可能导致调用者原有的代码出现问题,毕竟百度无法知道所有人都是怎么解析返回值的。这个时候最好的做法就是加版本号,保持原有版本,发布新的版本,所有问题迎刃而解。老用户也不用因为百度的升级,进行代码的更新,新用户又能享受最新的接口,完美。

判断是否要加版本号的方法:

是否明确的知道都有谁调用了你的接口,并且能通知到,如果能,那可以不加版本号;restful接口升级的时候,原有版本是否保留,如果不保留,可以不加版本号;

当然,加版本号是有一定技巧的,版本号应该放在一个功能模块的后面,甚至一个 url就应该自己独立的版本,如 api/user/v2,这样调用者就不会有整套接口都升级到 v2的错觉。

误区三 URI 中路径大小写问题

URL 中路径最好是小写,不要有驼峰式写法,比如下面接口错误写法

POST /orderItems/v1/1001

推荐写法

POST /orders/v1/items/1001

或者

/order-items/v1/1001总结

我见过很多采用基于微服务架构编写的微服务代码,大多数接口看似 restful 风格,然而仔细辨识才发现,原来是一堆的伪 restful 接口,要么动词名词不分,要么路径版本各种混乱。

实际上的场景是,restful 风格基本上停留在口口相传上,看起来逼格很高的东西也只能高高供起。大部分的程序员为了赶进度,完成 KPI,那还顾得上这种规范,一直在疯狂的打码中。

附录1 API 设计风格基本规则使用名词而不是动词

不要使用:

/getAllUsers /createNewUser /deleteAllUserGet 方法和查询参数不应该涉及状态改变

使用 PUT, POST 和 DELETE 方法 而不是 GET 方法来改变状态,不要使用 GET 进行状态改变:

使用复数名词

不要混淆名词单数和复数,为了保持简单,只对所有资源使用复数。

/cars 而不是 /car /users 而不是 /user /products 而不是 /product /settings 而部署 /setting使用子资源表达关系 如果一个资源与另外一个资源有关系,使用子资源:GET /cars/711/drivers/ 返回 car 711的所有司机 GET /cars/711/drivers/4 返回 car 711的4号司机使用 Http 头

相关推荐: